package com.itheima.health.utils;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;

import java.util.List;


public class ZookeeperLock {
    //连接zk服务端
    //创建临时序号节点
    CuratorFramework client = null;
    public ZookeeperLock(){
        ExponentialBackoffRetry retry = new ExponentialBackoffRetry(3000, 3);
        client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 1000, 1000, retry);
       client.start();
    }

    //获得锁
    public Lock lock(String lockId,long timeout){
        Lock lockNode = createLockNode(lockId);
        lockNode = tryActive(lockNode);
        if (!lockNode.getActive()){
            try {
                synchronized (lockNode){
                    lockNode.wait(timeout);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        return lockNode;
    }

    //激活锁
    public Lock tryActive(final Lock lock){
        //判断是否获得锁
        try {
            List<String> list = client.getChildren().forPath("/order");
            String firstPath = "/order/"+list.get(0);
            System.out.println(firstPath);
            System.out.println(lock.getPath());
            if (firstPath.equals(lock.getPath())){
                lock.setActive(true);
            }else {
                //添加上一个节点的监听
                final String upNodePath ="/order/"+ list.get(list.indexOf(lock.getPath().replace("/order/","")) - 1);
                final NodeCache nodeCache = new NodeCache(client, upNodePath);
                System.out.println(upNodePath);
                nodeCache.start(true);
                nodeCache.getListenable().addListener(new NodeCacheListener() {
                    @Override
                    public void nodeChanged() throws Exception {
                        System.out.println("节点删除:"+upNodePath);
                        Lock lock1 = tryActive(lock);
                        synchronized (lock){
                            if (lock1.getActive()){
                                lock.notify();
                            }
                        }
                        nodeCache.getListenable().removeListener(this);
                    }
                });
                //再尝试激活锁
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return lock;
    }
    //释放锁
    public void unlock(Lock lock){
        if (lock.getActive()){
            try {
                client.delete().forPath(lock.getPath());
                client.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //创建临时节点
    public Lock createLockNode(String lockId){
        Lock lock = new Lock();
        try {
            //创建写锁
            String path = client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).
                    forPath("/order/"+lockId);
            InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, "/readwrite");
            lock.setActive(false);
            lock.setLockId(lockId);
            lock.setPath(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return lock;
    }
}
